#ifndef DATACOLLECTORCONFIG_H__
#define DATACOLLECTORCONFIG_H__

#include <string>
#include <queue>
#include <filesystem>

class DiagOSAPI
{
public:
    using FilePairType = std::pair<std::string, unsigned char>;

    static int32_t Mkdir(const std::string& dirName);

    static int32_t CopyFile(const std::string& src, const std::string& dstDir);

    static int32_t CopyDir(const std::string& src, const std::string& dest);

    static int32_t RemoveF(const std::string& dirpath);

    static int32_t OSInfo(std::ostream& ss);

    static int32_t PackTargz(const std::string& curWorkspaceDir, const std::string& packName, const std::string& dirName);

    static int32_t FileSize(const std::string& path, uint64_t& sz);

    static int32_t TraverseDir(const std::string& dirpath, std::queue<FilePairType>& q);

    static int32_t IsDirExists(const std::filesystem::path& path)
    {
        bool res = (std::filesystem::exists(path) && std::filesystem::is_directory(path));
        return res ? 0 : -1;
    }

    template <typename Func> static int32_t TraverseDir(const std::string& dirpath, Func& func, bool recursive)
    {
        std::queue<FilePairType> q;
        if (0 != TraverseDir(dirpath, q))
        {
            return -1;
        }

        while (!q.empty())
        {
            auto pair = q.front();
            q.pop();

            func(pair);

            if (!recursive)
            {
                continue;
            }

            if (0 != TraverseDir(pair.first, q))
            {
                continue;
            }
        }

        return 0;
    }

    class DirSizeCBFunc
    {
    public:
        void operator()(const FilePairType& filepair)
        {
            uint64_t sz = 0;
            if (0 != FileSize(filepair.first, sz))
            {
                return;
            }
            dirSize += sz;
        }

        uint64_t dirSize = 0;
    };

    static int32_t DirSize(const std::string& dirpath, uint64_t& sz)
    {
        DirSizeCBFunc callback;

        if (0 != TraverseDir<DirSizeCBFunc>(dirpath, callback, true))
        {
            sz = 0;
            return -1;
        }

        sz = callback.dirSize;
        return 0;
    }

    class ListFileCBFunc
    {
    public:
        ListFileCBFunc(std::vector<std::string>& vec) : filelist(vec) {}

        void operator()(const DiagOSAPI::FilePairType& filepair);

        std::vector<std::string>& filelist;
    };

    class ListDirCBFunc
    {
    public:
        ListDirCBFunc(std::vector<std::string>& vec) : pathlist(vec) {}

        void operator()(const DiagOSAPI::FilePairType& filepair);

        std::vector<std::string>& pathlist;
    };

    template <typename CBFunc> class ListPath
    {
    public:
        int32_t operator()(const std::string& dirpath, std::vector<std::string>& filelist, bool recursive) const
        {
            CBFunc callback(filelist);
            if (0 != TraverseDir<CBFunc>(dirpath, callback, recursive))
            {
                filelist.clear();
                return -1;
            }
            return 0;
        }
    };

    static const ListPath<ListFileCBFunc> ListFile;
    static const ListPath<ListDirCBFunc> ListDir;

    static int32_t TopCpuLog(std::ostream& topLog);

    static int32_t TopMemLog(std::ostream& topLog);

    static int32_t IOTopDiskLog(std::ostream& topLog);

    static int32_t DumpSysLog(std::ostream& sysLog, uint32_t hour, uint32_t lineNum);

    static int32_t Popen(const std::string& cmd, std::ostream& out);
};

#endif  // DATACOLLECTORCONFIG_H__
